:- module(resource_access, [
        resource_size/3,
        resource_identificationTags/3,
        resource_language/3,
        resource_newVersionOf/3,
        resource_uses/3,
        resource_requires/3,
        resource_notes/3,
        resource_certification_status/3,
        resource_asset/3,
        resource_check/2,
        resource_update/3,
%% Types
        resource/1,
        resource_field/1
        ], [assertions,basicmodes,regtypes]).


:- comment(title, "Handling Information About Resources").
:- comment(subtitle, "AMOS Project").

:- comment(author, "Manuel Carro and the CLIP Group").
:- comment(author, "Facultad de Inform@'{a}tica").
:- comment(author, "Universidad Polit@'{e}cnica de Madrid").
:- comment(author, "@tt{clip@@dia.fi.upm.es}").
:- comment(author, "@tt{http://www.clip.dia.fi.upm.es/}").

:- comment(module, "

A resource is a piece of information the database knows how to search
for.  Every resource contains, at least, the information (description
terms) needed to express what capabilities are provided by the
resource, and which other capabilities are needed in order to use it
in a software project.  Every resource is part of a more general
class, the @em{asset}, which contains additional information about the
resource (e.g., where the resource can be located, etc.) which is
however not needed (and, in fact, not enough) as to distinguish
several resources from each other.

The operations herein included are aimed at creating and consulting
instances of the @em{resource} class.  They may change (for example,
to include more operations) should the ontology evolve in that
direction.


@include{three_argument_explanation.lpdoc}

@sp

@include{../Doc/acknowledgements.lpdoc}

@newpage
").

:- include(db('argnamesv/argnamesv')).   % Kludge to use local version
:- use_module(library(sort)).
:- use_module(db(certification_access)).
:- use_module(db(asset_access)).
:- use_module(db(dictionary_access)).
:- use_module(db(general_check)).
:- use_module(db(basic_types)).

:- argnames is_a_resource(
        size,
        identification,
        language,
        versionof,
        uses,
        requires,
        notes,
        cert_status,
        asset).


fields_and_types([
        field(size,            (nonnull, int) ),
        field(identification,  (nonnull, nonemptylist, list(ditem_or_stream))),
        field(language,        (null ; ditem)),
        field(versionof,       (null ; atm)),
        field(uses,            (null ; list(atom))),
        field(requires,        (null ; list(ditem_or_stream))),
        field(notes,           (null ; atom)),
        field(cert_status,     (null ; list(certification))),
        field(asset,           (nonnull, asset))]).

:- regtype resource_field(?Field)

 # "@var{Field} is a field of a resource definition.".
 %% 
 %%   It is currently defined as:
 %% 
 %% @includedef{resource_field/1}
 %% ".
 %% 
 %% resource_field(size).
 %% resource_field(identification).
 %% resource_field(language).
 %% resource_field(versionof).
 %% resource_field(uses).
 %% resource_field(requires).
 %% resource_field(notes).
 %% resource_field(cert_status).
 %% resource_field(asset).

resource_field(Field):- member(Field, is_a_resource$argnames).


:- regtype resource(?Res) # "@var{Res} is a resource.".

resource(is_a_resource${}).


:- pred resource_size(Res, Size, NewRes):

        resource * int * resource

# "@var{Size} is the (estimated) size of the resource @var{NewRes}.
There should be at least one size in every well-formed resource.".

resource_size(Res, Size, NewRes):-
	resource_update(Res,[size-Size], NewRes).


:- pred resource_identificationTags(Res, Tags, NewRes):

        resource * list(ditem) * resource

# "@var{Tags} is a list of terms which define the resource
@var{NewRes} in terms of the capabilities it provides.  @var{Tags}
must exist and it must @bf{not} be an empty list.".

%% Note that Tags is directly a list of items, instead of a
%% dictionary, as the description, etc. included in the dictionary is
%% of no use here.

resource_identificationTags(Res, Tags, NewRes):-
	resource_update(Res,[identification-Tags], NewRes).


:- pred resource_language(Res, Language, NewRes):

        resource * ditem * resource

# "@var{Language} is the programming language used in the
implementation of the resource @var{NewRes}.".

resource_language(Res, Language, NewRes):-
	resource_update(Res,[language-Language], NewRes).


:- pred resource_newVersionOf(Res, Forerunner, NewRes):

        resource * atm * resource

# "@var{Forerunner} is the name of the resource @var{NewRes} is a
new version of.".

resource_newVersionOf(Res, Forerunner, NewRes):-
	resource_update(Res,[forerunner-Forerunner], NewRes).


:- pred resource_uses(Res, Uses, NewRes):

        resource * list(resource) * resource

# "@var{Uses} is the list of resources (determined by their unique
name) which can be used when working with the resource @var{NewRes}.
They are not intended to be strong requirements, but their presence
might help in compiling, linking, etc. @var{NewRes}.  The list of
used resources may be empty.".

resource_uses(Res, Uses, NewRes):-
	resource_update(Res,[uses-Uses], NewRes).


:- pred resource_requires(Res, Requires, NewRes):

        resource * list(ditem) * resource

# "@var{Requires} is the list of capabilities which must be present to
fully use the resource @var{NewRes}.  They represent strong
requirements which will be taken into account when performing a
search.".

resource_requires(Res, Requires, NewRes):-
	resource_update(Res,[requires-Requires], NewRes).


:- pred resource_notes(Res, Notes, NewRes):

        resource * string * resource

# "@var{Notes} is a list of miscellaneous notes regarding the resource
@var{NewRes}.".

resource_notes(Res, Notes, NewRes):-
	resource_update(Res,[notes-Notes], NewRes).


:- pred resource_certification_status(Res, Certification, NewRes):

        resource * list(certification) * resource

# "@var{Certification} is the list of certificates of the resource
@var{NewRes}.".

resource_certification_status(Res, Certification, NewRes):-
	resource_update(Res,[cert_status-Certification], NewRes).


:- pred resource_asset(Res, Asset, NewRes):
        resource * asset * resource

# "@var{Asset} is the (more general) asset the resource @var{NewRes}
defines.".

resource_asset(Res, Asset, NewRes):-
	resource_update(Res,[asset-Asset], NewRes).



:- pred resource_check(?Res, ?WrongFields):
        resource * list(resource_field)

# "The already formed resource @var{Res} is checked against
the constraints specified in the ontology definition.  
@include{check_definition.lpdoc}".


%resource_check(_Res, _WrongFields). 

resource_check(Res, WrongFields):-
        fields_and_types(F),
        check_each_field(F, Res, WrongFields).

check_each_field([], _Res, []).
check_each_field([field(F, T)|Fs], Res, W):-
        Res = is_a_resource${F => V},
        (
            check_field(T, V) ->
            W = RestW
        ;
            W = [F|RestW]
        ),
        check_each_field(Fs, Res, RestW).



:- pred resource_update(+Res, +PairList, ?NewRes):
        resource * list(pair) * resource

# "It updates @var{Res} to give @var{NewRes}.  @var{PairList} is a
list of pairs (see @pred{pair}): dash-separated ground terms
@tt{Field-Value}, which are meant to express the name of a field and
its update value.  @tt{Asset update} is a general call upon which all
the rest of the @tt{update} calls rely.".


resource_update(Res, PairList, NewRes):-
        NewRes = is_a_resource${},               % New asset skeleton
        sort(is_a_resource$argnames, AllFields),
        keysort(PairList, SortedPairList),  %% All sorted in same order now
        update(AllFields, SortedPairList, Res, NewRes).

update([], _, _, _).
update([Field|Fields], [Field-NewValue|ToUpdate], Res, NewRes):-
        !,
        NewRes = is_a_resource${Field => NewValue},
        update(Fields, ToUpdate, Res, NewRes).
update([Field|Fields], ToUpdate, Res, NewRes):-
        Res = is_a_resource${Field => Value}, 
        NewRes = is_a_resource${Field => Value}, 
        update(Fields, ToUpdate, Res, NewRes).


:- comment(version_maintenance,on).

:- comment(version(0*1+2,2003/07/04,12:55*38+'CEST'), "Changed
   use_module and include references to use directory aliases.  (Jesus
   Correas Fernandez)").

:- comment(version(0*1+1,2003/02/14,16:28*01+'CET'), "ResAfter to
NewRes (Manuel Carro)").

:- comment(version(0*1+0,2003/02/13,20:49*41+'CET'), "Initial version,
with all interfaces included.  (Manuel Carro)").

